package com.xxx.crypto;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

/**
 * @author leiming
 * @Description
 * @date 13:33 2019-03-21
 **/
public class RSAUtil {

    // 加密算法类型
    private static final String KEY_ALGORITHM = "RSA";

    // 密钥长度
    private static final int KEY_SIZE = 512;

    // 公钥Key名称
    private static final String PUBLIC_KEY_NAME = "RSAPublicKey";

    // 私钥Key名称
    private static final String PRIVATE_KEY_NAME = "RSAPrivateKey";

    
    /**
     * description: 初始化密钥对
     * 
     * @author: leiming
     * @date: 2019-03-21 13:38
     * @param: 
     * @return: 
     */
    public static Map<String, Object> initKey() throws Exception {
        // 实例化密钥生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        
        // 初始化密钥生成器
        keyPairGenerator.initialize(KEY_SIZE);
        
        // 生成密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        
        // 甲方公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        
        // 甲方私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        
        // 将密钥存储在map中
        Map<String, Object> keyMap = new HashMap<String, Object>();
        keyMap.put(PUBLIC_KEY_NAME, publicKey);
        keyMap.put(PRIVATE_KEY_NAME, privateKey);
        
        return keyMap;
    }

    /**
     * description: 取得公钥
     *
     * @author: leiming
     * @date: 2019-03-21 13:42
     * @param: keyMap
     * @return:
     */
    public static String getPublicKey(Map<String, Object> keyMap) {
        Key key = (Key) keyMap.get(PUBLIC_KEY_NAME);
        return Base64.encodeBase64String(key.getEncoded());
    }

    /**
     * description: 获取私钥
     *
     * @author: leiming
     * @date: 2019-03-21 13:42
     * @param: keyMap
     * @return:
     */
    public static String getPrivateKey(Map<String, Object> keyMap) {
        Key key = (Key) keyMap.get(PRIVATE_KEY_NAME);
        return Base64.encodeBase64String(key.getEncoded());
    }

    /**
     * description: 私钥加密
     *
     * @author: leiming
     * @date: 2019-03-21 13:46
     * @param: data
     * @param: key
     * @return:
     */
    public static String encryptByPrivateKey(String data, String key) throws Exception {
        Cipher cipher = generatePrivate(Cipher.ENCRYPT_MODE, key);
        return Base64.encodeBase64String(cipher.doFinal(data.getBytes()));
    }

    /**
     * description: 私钥解密
     *
     * @author: leiming
     * @date: 2019-03-21 13:46
     * @param: data
     * @param: key
     * @return:
     */
    public static String decryptByPrivateKey(String data, String key) throws Exception {
        Cipher cipher = generatePrivate(Cipher.DECRYPT_MODE, key);
        return new String(cipher.doFinal(Base64.decodeBase64(data)));
    }

    /**
     * description: 公钥加密
     *
     * @author: leiming
     * @date: 2019-03-21 13:46
     * @param: data
     * @param: key
     * @return:
     */
    public static String encryptByPublicKey(String data, String key) throws Exception {
        Cipher cipher = generatePublic(Cipher.ENCRYPT_MODE, key);
        return Base64.encodeBase64String(cipher.doFinal(data.getBytes()));
    }

    /**
     * description: 公钥解密
     *
     * @author: leiming
     * @date: 2019-03-21 13:46
     * @param: data
     * @param: key
     * @return:
     */
    public static String decryptByPublicKey(String data, String key) throws Exception {
        Cipher cipher = generatePublic(Cipher.DECRYPT_MODE, key);
        return new String(cipher.doFinal(Base64.decodeBase64(data)));
    }

    private static Cipher generatePublic(int mode, String key) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(key));

        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(mode, publicKey);

        return cipher;
    }

    private static Cipher generatePrivate(int mode, String key) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key));
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        cipher.init(mode, privateKey);

        return cipher;
    }

    public static void main(String[] args) {

        try {
            // 初始化密钥
//            Map<String, Object> keyMap = RSAUtil.initKey();
//
//            String publicKey = RSAUtil.getPublicKey(keyMap);
//            String privateKey = RSAUtil.getPrivateKey(keyMap);
//
//            String myTestStr = "301431552747666244@1553148336000@1234567890";
//
//            System.out.println("公钥:" + publicKey);
//            System.out.println("私钥:" + privateKey);
//
//            System.out.println("\n私钥加密，公钥解密");
//            String codePrivate = RSAUtil.encryptByPrivateKey(myTestStr, privateKey);
//            System.out.println("私钥加密：" + codePrivate);
//            String decodePrivate = RSAUtil.decryptByPublicKey(codePrivate, publicKey);
//            System.out.println("公钥解密：" + decodePrivate);
//            System.out.println("原文对比：" + myTestStr);
//
//            System.out.println("\n公钥加密，私钥解密");
//            String codePublic = RSAUtil.encryptByPublicKey(myTestStr, publicKey);
//            System.out.println("公钥加密：" + codePublic);
//            String decodePublic = RSAUtil.decryptByPrivateKey(codePublic, privateKey);
//            System.out.println("私钥解密：" + decodePublic);
//            System.out.println("原文对比：" + myTestStr);

            String publicKey = "77c9e339f96d425ba8ce6907cfe17517_NAPP";
//            publicKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIc6y11ELuBqI1nAR+xBoypNKvdqiz0sQ6Cazp2c0dr8tcDxl9pgjMtOTuzvnYSVyE6zReusRGwIOZQ45EskoykCAwEAAQ==";


            String runningNumber = "1553166324317";
            long startTime = System.currentTimeMillis();
            String timestamp = String.valueOf(startTime);
            String nonceStr = "1234567890";

            String codePrivate = runningNumber + "@" + timestamp + "@" + nonceStr;
            System.out.println(codePrivate);
            System.out.println(RSAUtil.encryptByPublicKey(codePrivate, publicKey));
            long stopTime = System.currentTimeMillis();
            System.out.println("Time: " + String.valueOf(stopTime - startTime));
//            String privateKey = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA0gasJaf2A/UvqY1pd+h8ZqJ3ChgZwviRkQsPTrOkiPQcB1KYpoxCLbdQ9jLfzAb3C74wXLbS2dp3Ip8dAaxCnwIDAQABAkEAtJgaNHL9nx+YcUHwm7OkLJispVhd5oHYoZCSBAmChGNcODpY7pVgXSvQL/4BAIHLP/7x6CnV2I7aV92jvqSxcQIhAO7bg+D129NmjrlSqSO2hIoFMvVPRk5nvfPrGHgiHmhHAiEA4RlxZOu6/99Nfeef4X8DIPwV4bakPK1KrUenJ26M1ukCIQDRpkU7yDB5fhQZ387rtMDisCuJG1rXaMFWfexNTY0o8wIgccDo1AZoruvK/mhyHIOSMjYSXMluwBcW2PCP4VZ1qBkCIFLrVMC+vcS9mU9SyYlcNGsodHX5ultofExI45QIb+4v";
//            String verStr = "poeugI+ET1Dafn7FU8QlS+IiaJi4BSFQDr96Ok2s6E+LJgGgS1FzNcyXf6nYQi97SgkvnzzrvpDfxb1Yicrukg==";
//            System.out.println("解密：" + RSAUtil.decryptByPrivateKey(verStr, privateKey));
        }catch (Exception e){
            System.out.println(e);
        }


    }
}
